#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

// 定义事件数据结构（移除了ret字段）
struct event
{
    u32 ret;
    u32 pid;         // 进程ID
    u32 uid;         // 用户ID
    u32 flags;       // 打开标志（如O_RDONLY, O_WRONLY等）
    char comm[16];   // 进程名
    char fname[128]; // 文件名
};

// 定义环形缓冲区映射
struct
{
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, sizeof(struct event) * 1024 * 2);
} events SEC(".maps");

struct
{
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, sizeof(struct event) * 1024 * 2);
} exit_events SEC(".maps");

struct
{
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 10240);
    __type(key, u32); // 线程ID(tid)
    __type(value, struct event);
} tmp_storage SEC(".maps");

char LICENSE[] SEC("license") = "Dual BSD/GPL";

SEC("tracepoint/syscalls/sys_enter_openat")
int handle_enter(struct trace_event_raw_sys_enter *ctx)
{
    u64 id = bpf_get_current_pid_tgid();
    u32 tid = (u32)id;
    u32 uid = (u32)bpf_get_current_uid_gid();

    struct event e = {};
    e.pid = id >> 32;
    e.uid = uid;
    e.flags = (u32)ctx->args[2]; // 打开标志

    bpf_get_current_comm(&e.comm, sizeof(e.comm));

    const char *fname = (const char *)ctx->args[1];
    bpf_probe_read_user_str(e.fname, sizeof(e.fname), fname);

    // 存储到临时映射供exit使用
    bpf_map_update_elem(&tmp_storage, &tid, &e, BPF_ANY);

    // 发送到进入事件ringbuffer
    bpf_ringbuf_output(&events, &e, sizeof(e), 0);

    return 0;
}

SEC("tracepoint/syscalls/sys_exit_openat")
int handle_exit(struct trace_event_raw_sys_exit *ctx)
{
    u32 tid = (u32)bpf_get_current_pid_tgid();

    // 从临时存储中获取进入事件
    struct event *e = bpf_map_lookup_elem(&tmp_storage, &tid);
    if (!e)
        return 0;

    // 创建退出事件（复制基本信息）
    struct event exit_event = *e;
    exit_event.ret = ctx->ret; // 设置返回值

    // 发送到退出事件ringbuffer
    bpf_ringbuf_output(&exit_events, &exit_event, sizeof(exit_event), 0);

    // 清理临时存储
    bpf_map_delete_elem(&tmp_storage, &tid);

    return 0;
}
